package service

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"time"

	"net/url"

	"gitee.com/huangxinbo/xcas/internal/app/base"
	"gitee.com/huangxinbo/xcas/internal/asynq_handle_routes"
	"gitee.com/huangxinbo/xcas/internal/dao"
	"gitee.com/huangxinbo/xcas/internal/model"
	"gitee.com/huangxinbo/xcas/internal/model/db_model"
	"gitee.com/huangxinbo/xcas/pkg"
	"gitee.com/huangxinbo/xcas/pkg/asynq_instance"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
)

type ChacaptchaType string

const (
	CaptchaTypeRandom ChacaptchaType = "random"
	CaptchaTypeUUIDV4 ChacaptchaType = "uuidv4"
)

type VerificationService struct {
	base    *base.Base
	dao     *dao.DAO
	service *Service
}

func NewVerificationService(base *base.Base, dao *dao.DAO, service *Service) *VerificationService {
	return &VerificationService{
		base:    base,
		dao:     dao,
		service: service,
	}
}

// generateToken generates a random token
func (s *VerificationService) generateToken(t ChacaptchaType) string {
	var captcha string
	switch t {
	case CaptchaTypeRandom:
		captcha = pkg.GenerateRandom(6)
	case CaptchaTypeUUIDV4:
		id := uuid.New()
		captcha = id.String()
	default:
		id := uuid.New()
		// 生成 UUID v4 字符串形式
		captcha = id.String()
	}
	return captcha
}

// generateCaptcha generates a random token
// CreateEmailCaptcha creates a new email captcha for email modification
func (s *VerificationService) CreateEmailCaptcha(ctx *gin.Context, email string) (string, error) {
	// Generate token
	token := s.generateToken("random")

	// Create verification record
	verification := &db_model.Verification{
		Type:       db_model.VerificationTypeEmail,
		Identifier: email,
		VerifyCode: token,
		ExpiredAt:  time.Now().Add(10 * time.Minute), // 10分钟有效期
	}

	if err := s.dao.VerificationDAO.Create(ctx, verification); err != nil {
		s.base.Logger.Error("Failed to create email captcha record", zap.Error(err))
		return "", err
	}

	// Send email captcha
	// if s.mail != nil {
	// 	if err := s.mail.SendEmailCaptcha(email, token); err != nil {
	// 		s.base.Logger.Error("Failed to send email captcha", zap.Error(err))
	// 		return "", err
	// 	}
	// } else {
	// 	s.base.Logger.Warn("Mail service not available, skipping email sending")
	// }

	s.base.Logger.Info("Email captcha created and sent",
		zap.String("email", email),
		zap.String("captcha", token))

	return token, nil
}

// CreateMobileCaptcha creates a new mobile captcha for mobile modification
func (s *VerificationService) CreateMobileCaptcha(ctx *gin.Context, mobile string) (string, error) {
	// Generate token
	token := s.generateToken("random")

	// Create verification record
	verification := &db_model.Verification{
		Type:       db_model.VerificationTypeMobile,
		Identifier: mobile,
		VerifyCode: token,
		ExpiredAt:  time.Now().Add(10 * time.Minute), // 10分钟有效期
	}

	if err := s.dao.VerificationDAO.Create(ctx, verification); err != nil {
		s.base.Logger.Error("Failed to create mobile captcha record", zap.Error(err))
		return "", err
	}

	// Send mobile captcha
	// TODO: 需要注入短信服务
	// if err := s.smsService.SendMobileCaptcha(mobile, token); err != nil {
	// 	s.base.Logger.Error("Failed to send mobile captcha", zap.Error(err))
	// 	return "", err
	// }

	s.base.Logger.Info("Mobile captcha created and sent",
		zap.String("mobile", mobile),
		zap.String("captcha", token))

	return token, nil
}

// CreateRegisterVerification creates a register verification record and sends email
func (s *VerificationService) CreateRegisterVerification(ctx *gin.Context, email string, verificationType db_model.VerificationType) (string, error) {
	// Generate token
	token := s.generateToken("uuidv4")

	// Create verification data
	verificationData := model.VerificationData{
		Email: email,
		Token: token,
	}

	// Encode to base64
	jsonData, err := json.Marshal(verificationData)
	if err != nil {
		s.base.Logger.Error("Failed to marshal verification data", zap.Error(err))
		return "", err
	}
	base64Data := base64.URLEncoding.EncodeToString(jsonData)
	queryEscaped := url.QueryEscape(base64Data)

	// Create verification record
	verification := &db_model.Verification{
		Type:       verificationType,
		Identifier: email,
		VerifyCode: token,
		ExpiredAt:  time.Now().Add(24 * time.Hour), // 24小时有效期
	}

	if err := s.dao.VerificationDAO.Create(ctx, verification); err != nil {
		s.base.Logger.Error("Failed to create verification record", zap.Error(err))
		return "", err
	}

	// Generate verification link
	verificationLink := fmt.Sprintf("%s/cas/register?validate=%s", pkg.GetEnvString("SERVER.URL", ""), queryEscaped)

	payload := asynq_handle_routes.RouteEmailRegisterVerificationPayload{
		VerificationLink: verificationLink,
		ToEmail:          email,
	}
	task := asynq_instance.NewAsynqTask(s.base, asynq_handle_routes.RouteEmailRegisterVerification, payload)
	s.base.AsynqClient.Enqueue(task)

	return token, nil
}

// CreateForgotPasswordVerification creates a forgot password verification record and sends email
func (s *VerificationService) CreateForgotPasswordVerification(ctx *gin.Context, email string) (string, error) {
	// Generate token
	token := s.generateToken("uuidv4")

	// Create verification data
	verificationData := model.VerificationData{
		Email: email,
		Token: token,
	}

	// Encode to base64
	jsonData, err := json.Marshal(verificationData)
	if err != nil {
		s.base.Logger.Error("Failed to marshal verification data", zap.Error(err))
		return "", err
	}
	base64Data := base64.URLEncoding.EncodeToString(jsonData)
	queryEscaped := url.QueryEscape(base64Data)

	// Create verification record
	verification := &db_model.Verification{
		Type:       db_model.VerificationTypeForgot,
		Identifier: email,
		VerifyCode: token,
		ExpiredAt:  time.Now().Add(1 * time.Hour), // 1小时有效期
	}

	if err := s.dao.VerificationDAO.Create(ctx, verification); err != nil {
		s.base.Logger.Error("Failed to create forgot password verification record", zap.Error(err))
		return "", err
	}

	// Generate verification link
	verificationLink := fmt.Sprintf("%s/cas/forgot?validate=%s", pkg.GetEnvString("SERVER.URL", ""), queryEscaped)
	s.base.Logger.Info("Send forgot password verification email", zap.String("verificationLink", verificationLink))

	payload := asynq_handle_routes.RouteEmailForgotVerificationPayload{
		VerificationLink: verificationLink,
		ToEmail:          email,
	}
	task := asynq_instance.NewAsynqTask(s.base, asynq_handle_routes.RouteEmailForgotVerification, payload)
	s.base.AsynqClient.Enqueue(task)

	return token, nil
}

// VerifyToken verifies a token
func (s *VerificationService) VerifyToken(ctx *gin.Context, email, token string, verificationType db_model.VerificationType) (bool, error) {
	verification, err := s.dao.VerificationDAO.GetByIdentifierAndType(ctx, email, verificationType)
	if err != nil {
		return false, err
	}

	if verification == nil {
		return false, nil
	}

	// Check if token matches and is not expired
	if verification.VerifyCode == token && verification.ExpiredAt.After(time.Now()) {
		// Delete the verification record after successful verification
		if err := s.dao.VerificationDAO.Delete(ctx, verification.ID); err != nil {
			s.base.Logger.Warn("Failed to delete verification record after verification", zap.Error(err))
		}
		return true, nil
	}

	// Delete expired verification record
	if verification.ExpiredAt.Before(time.Now()) {
		if err := s.dao.VerificationDAO.Delete(ctx, verification.ID); err != nil {
			s.base.Logger.Warn("Failed to delete expired verification record", zap.Error(err))
		}
	}

	return false, nil
}

// CleanupExpiredVerifications deletes expired verification records
func (s *VerificationService) CleanupExpiredVerifications(ctx *gin.Context) error {
	return s.dao.VerificationDAO.DeleteExpired(ctx)
}
